/*
-----------------------------------------------------------------------------
This source file is part of DIVA
The project of Software Engineering Lab, dept. of CSIE, NTNU.

Copyright (c) 2000-2006 The Software Engineering Lab, dept. of CSIE, NTNU.
-----------------------------------------------------------------------------
Filename:		DIVA_VM.cpp
Description:	實作關於DIVA_VM.h中的建構子及之後可能會增加的method
name:			momo
update histroy	08/29	增加DIVA_VM(xParameterPack)的建構子提供給child vm的建構子
						使用
				08/29	增加isPosFix(x,y,z)只要三個參數有一個link，這個vm即是固定
						同時沒給定的參數(x,y,z)自動給0

name:			hyt
update history  10/20 
				增加共用mehtod
						(1) VL_createEntity , 建立vm的entity
						(2) VL_regBoundingBox , registe VM的bounding box 
						(3) VL_arrangeVMs , 排列cpvm內的內容物
						(4) VL_computeMaxBoundingsize , 計算所需的最大boudingbox size
						(5) VL_computeMinBoundingsize , 計算所需的最小boudingbox size
						(6) VL_setVMsPosition , 設定cpvm內容物的position
						(7) VL_minimizeVMsize , 縮小cpvm內容物
						(8) VL_propagateMouseEvent , VMPick的滑鼠事件
						(9) VL_setEntityColor , 設定entity顏色
						(10) VL_getVMMovableObjectTable , get MovableObject table
						(11) VL_createTextNode , 建立vm的text node
						(12) VL_createVMtext , 建立vm的text內容
						(13) VL_updateText , 更新vm的text內容

						2009/07/15 by frank
						增加改變透明度的方法 init_transparency() 和 update_transparency()

-----------------------------------------------------------------------------
*/
#include "DIVA_VM.h"
#include "xParameterPack.h"
#include "DIVA_Manager.h"
#include "transparency.h"
#include "EntityMaterialInstance.h"
#include "MappingEngine.h"

#define COLOR_MODULATE_PARAM_INDEX 1  // hyt 08/10/20
static const double INIT_VM_SCALE = 1.0 ;
static const double INIT_RGB = 0.0 ;
static const double INIT_TRANSPARENCY = 1.0 ;

DIVA_VM::DIVA_VM(xParameterPack xpp){

	assert(&xpp);

	_para_onoff = xpp.para_onoff ;
	_name =  xpp.paras[0].val_string;
	_vm_name_position=xpp.paras[1].val_int; 

	_vm_rx=xpp.paras[RC].val_float_ptr;
	_vm_ry=xpp.paras[RC+1].val_float_ptr;
	_vm_rz=xpp.paras[RC+2].val_float_ptr;

	_vm_sizex=xpp.paras[SIZE].val_float_ptr;
	_vm_sizey=xpp.paras[SIZE+1].val_float_ptr;
	_vm_sizez=xpp.paras[SIZE+2].val_float_ptr;

	_vm_sizexscale=xpp.paras[SCALE].val_double_ptr;
	_vm_sizeyscale=xpp.paras[SCALE+1].val_double_ptr;
	_vm_sizezscale=xpp.paras[SCALE+2].val_double_ptr;

	_vm_r = xpp.paras[RGB].val_double_ptr ;
	_vm_g = xpp.paras[RGB+1].val_double_ptr ;
	_vm_b = xpp.paras[RGB+2].val_double_ptr ;

	_vm_transparency = xpp.paras[TRANS].val_double_ptr ;

	_vm_yaw = xpp.paras[ROTATE].val_int_ptr ;
	_vm_pitch = xpp.paras[ROTATE+1].val_int_ptr ;
	_vm_roll = xpp.paras[ROTATE+2].val_int_ptr; 

	_vm_quat = xpp.paras[QUAT].val_quaternion_ptr ;

	_vm_clickmsg = xpp.paras[CLICKMSG].val_string_ptr ;
	_vm_clickmsg_position = xpp.paras[CLICKMSG+1].val_int ;

	for (int i=SKIP_NAME ; i<= SKIP_CLICKMSG; i++) {
		_prohibit_defaults[i] = false; 
	}

	_ent = NULL ;
	_name_scene_node = NULL;
	_movable = true;
	_visible = true ;
	
}


void DIVA_VM::VMDragged(Ogre::Real screenx, Ogre::Real screeny,
						Ogre::Real absx,Ogre::Real absy,Ogre::Real absz){

    if (_visible == false) return ;

	if (isDraggedOn()) {           // only when _dragged is true then we can set the position
		this->setPosition(absx,absy,absz);
		// Since this VM is dragged, its Out port such as (_vm_rx, _vm_ry, _vm_rz) may changes
		// we should update the whole mapping tree to make the new position information
		// passed to other mapping node that use the information
		xMappingNode* p = MappingEngine::getInstance()->xSearchNodeByVM(this);
		xMappingTree * xmt = MappingEngine::getInstance()->getRootxMappingTree(p);
		xmt->update();
	}
}

void DIVA_VM::VMPicked(Ogre::Real x, Ogre::Real y, Ogre::Real z) {

	if (_visible == false) return ;

	if (_vm_clickmsg == NULL) return ;
	if (!_textvisible) {
		string result = replace_clickmsg() ;
		_msg->setCaption(result);
		_msg->setVisible(true);
		_textvisible = true ;
	} else {
		_msg->setVisible(false);
		_textvisible = false ;
	}
}
void DIVA_VM::VMValueUpdated() {
	if (_visible == false) return ;
	update_private_attrs_started();
	update_position();
	update_size_and_scale();
	update_color_and_transparency();
	update_rotation();
	update_quaternion();

	update_private_attrs_ended();
	// click msg must be outside the bounding box
	// so we wait for any scaling and rotation to complete 	

	generate_valstring();
	update_clickmsg(); 
}

void DIVA_VM::VMSetVisible(bool vis) {
	if (_visible != vis) {
		  _visible = vis ;
        _SceneNode->setVisible(vis);
	}
}



void DIVA_VM::init_default_parameters() {

	_vm_rx_val = -9999 ;
	_vm_ry_val = -9999 ;
	_vm_rz_val = -9999 ;

	_vm_init_sizex = -1 ;  // the initial size should be reset in load_3Dresources() 
	_vm_init_sizey = -1 ;  // if not, assert failed at init_size_and_scale() ;
	_vm_init_sizez = -1 ;

	_vm_sizex_val = -1 ;
	_vm_sizey_val = -1 ;
	_vm_sizez_val = -1 ;

	_vm_sizexscale_val = -1 ;
	_vm_sizeyscale_val = -1 ;
	_vm_sizezscale_val = -1 ;

	_vm_r_val = _vm_g_val = _vm_b_val = _vm_transparency_val = -1 ;

	_vm_yaw_val = -9999 ;
	_vm_roll_val = -9999 ;
	_vm_pitch_val = -9999 ;



	// the code here is based on template design pattern
	load_3Dresources();
	reg_event_entity();
	
	set_default_values();

	init_private_attrs_started();
	// check if the (rx,ry,rz) is connected to any variable 
	init_position();
	// check if (sizex, sizey, sizez) is connected to any variable
	init_size_and_scale();
	// If (sizex, sizey, sizez) has been connected to any variable
	// it should prohibit the effect of connecting to (scalex, scaley, scalez)
	// ehck if (scalex, scaley, scalez) is connected to any variable	

	// after the necessary scaling is done, we print the variable name on 6 positions
	init_color_and_transparency();
	init_rotation();
	// init_transparency(); deprecated. Already handled in init_color
	init_quaternion();
	init_private_attrs_ended();
	
	// click msg must be outside the bounding box
	// so we wait for any scaling and rotation to complete 	
	init_print_name();
	init_clickmsg();  
	generate_valstring();
	

	
}

void DIVA_VM::generate_valstring() {
	std::ostringstream oss ;
	oss << _vm_rx_val ;	_vm_rx_str = oss.str();
	oss.clear() ; 	oss << _vm_ry_val ; _vm_ry_str = oss.str();
 	oss.clear() ; 	oss << _vm_rz_val ; _vm_rz_str = oss.str();
 
	oss.clear() ;	oss << _vm_sizex_val ;	_vm_sizex_str = oss.str();
	oss.clear() ;	oss << _vm_sizey_val ;	_vm_sizey_str = oss.str();
	oss.clear() ;	oss << _vm_sizez_val ;	_vm_sizez_str = oss.str();

	oss.clear() ;	oss << _vm_sizexscale_val ;	_vm_sizexscale_str = oss.str();
	oss.clear() ;	oss << _vm_sizeyscale_val ;	_vm_sizeyscale_str = oss.str();
	oss.clear() ;	oss << _vm_sizezscale_val ;	_vm_sizezscale_str = oss.str();

	oss.clear() ;	oss << _vm_r_val ;	_vm_r_str = oss.str();
	oss.clear() ;	oss << _vm_g_val ;	_vm_g_str = oss.str();
	oss.clear() ;	oss << _vm_b_val ;	_vm_b_str = oss.str();
	oss.clear() ;	oss << _vm_transparency_val ;	_vm_transparency_str = oss.str(); 

	oss.clear() ;	oss << _vm_yaw_val ;	_vm_yaw_str = oss.str();
	oss.clear() ;	oss << _vm_pitch_val ;	_vm_pitch_str = oss.str();
	oss.clear() ;	oss << _vm_roll_val ;	_vm_roll_str = oss.str();
	
	oss.clear() ;	oss << _vm_quat_val ;	_vm_quat_str = oss.str();
	
}
void DIVA_VM::setPosition(Ogre::Vector3 pos){

	assert(_ParentSceneNode != NULL);
	_SceneNode->setPosition(pos);	
	
	position = pos ;
	_vm_rx_val = pos.x ;
	_vm_ry_val = pos.y ;
	_vm_rz_val = pos.z ;
	std::ostringstream oss ;
	oss << _vm_rx_val ;	_vm_rx_str = oss.str();
	oss.str(std::string());
	oss.clear() ; 	
	oss << _vm_ry_val ;
	_vm_ry_str = oss.str();
	oss.str(std::string());
 	oss.clear() ; 	
	oss << _vm_rz_val ; 
	_vm_rz_str = oss.str();

}
void DIVA_VM::init_print_name() {

	if (_prohibit_defaults[SKIP_NAME] == true) 
		return ;

	// FIRST, print the variale name
	if (_name != "") {
		// add a text on the left side of the mesh 
		// we must use MovableText to prevent _msg from being clicked
		_namemsg = VL_createVMtext(_name,"MovableText");
		_name_scene_node = VL_createTextNode((TextPosition)_vm_name_position);		

		_name_scene_node->setInheritScale(false);
		_name_scene_node ->attachObject(_namemsg);
		_namemsg->setCharacterHeight(30);		
		_namemsg->setColor(Ogre::ColourValue(0.0,1.0,0.5, 1.0f)); // initialize the text color to be green
	}
}
string DIVA_VM::replace_clickmsg() {
	return _vm_clickmsg_val ;
}
void DIVA_VM::init_clickmsg() {
	if (_prohibit_defaults[SKIP_CLICKMSG] == true) 
		return ;

	if (_vm_clickmsg != NULL) {
			_vm_clickmsg_val = * _vm_clickmsg ;
			string result = replace_clickmsg();
			_msg = VL_createVMtext(result,"MovableText");
			_msg->setVisible(false);
			_text_scene_node = VL_createTextNode((TextPosition)_vm_clickmsg_position);	
			_text_scene_node->setInheritScale(false);
			_text_scene_node ->attachObject(_msg);
			_msg->setCharacterHeight(40);		
			_msg->setColor(Ogre::ColourValue(1.0,5.0,0.5, 1.0f)); // init the text color to be red
			_textvisible = false ;
	}

}
void DIVA_VM::update_clickmsg() {
	if (_prohibit_defaults[SKIP_CLICKMSG] == true) 
		return ;

	if (_vm_clickmsg != NULL) {
		_vm_clickmsg_val = (*_vm_clickmsg);
		string result = replace_clickmsg();
		_msg->setCaption(result);		
	}

}
void DIVA_VM::init_position(){


	if (_prohibit_defaults[SKIP_POSITION] == true) 	return ;  // initialize position is set to be skipped

	assert(_vm_rx_val != -9999 && _vm_ry_val != -9999 && _vm_rz_val != -9999);
	// when this assert false is reached, this VM's set_default_values() are not well implemented

	if (_para_onoff[RC] || _para_onoff[RC+1] || _para_onoff[RC+2]) {
		if (_vm_rx)	_vm_rx_val = (*_vm_rx) ;
		if (_vm_ry) _vm_ry_val = (*_vm_ry) ;
		if (_vm_rz)	_vm_rz_val = (*_vm_rz) ;
		this->setPosition(_vm_rx_val,_vm_ry_val,_vm_rz_val);

		// if any of the pointer is set by connecting the variable
		// or by setting the default value in the mapping dialog,
		if (_vm_rx || _vm_ry || _vm_rz)  this->disableVMDraggeed();
	}

}
void DIVA_VM::update_position(){

	init_position();
}
void DIVA_VM::init_size_and_scale(){

	// paramters (sizex, sizey, sizez) and (sizexscale, sizeyscale, sizezscale) can be connected to a 
	// complicated combination and should be considered as a whole

	if (_prohibit_defaults[SKIP_SIZE] == true) return ;  
	if (_prohibit_defaults[SKIP_SCALE] == true) return ;

	assert(_vm_init_sizex >= 0 && _vm_init_sizey >= 0 && _vm_init_sizez >= 0 ) ;//modify by hyt
	assert(_vm_sizex_val >= 0 && _vm_sizey_val >= 0 && _vm_sizez_val >= 0) ;//modify by hyt
	assert(_vm_sizexscale_val >= 0 &&  _vm_sizeyscale_val >= 0 &&  _vm_sizezscale_val >= 0);//modify by hyt
	// the three variables should be set correctly in set_default_values()

	// case 1:
	//   (sizex, sizey, sizez) and (sizexscale, sizeyscale, sizezscale) have not been connected to variables
	//   however, some parameters may have default values other than zeros. 
	if (_para_onoff[SIZE] == false && _para_onoff[SIZE+1] == false && _para_onoff[SIZE+2] == false &&
		_para_onoff[SCALE] == false && _para_onoff[SCALE+1] == false && _para_onoff[SCALE+2] == false)
	{
		if (_vm_sizex || _vm_sizey || _vm_sizez) {
			// some parameters have default value set in the portattr dialog
			if(_vm_sizex != NULL)  _vm_sizex_val= (*_vm_sizex);
			if(_vm_sizey != NULL)  _vm_sizey_val= (*_vm_sizey);
			if(_vm_sizez != NULL)  _vm_sizez_val= (*_vm_sizez);
			this->scaleBodyToAbsSize(_vm_sizex_val,_vm_sizey_val,_vm_sizez_val ) ;
			// setting the size of a VM is equal to set the scale 
			_vm_sizexscale_val = (double)_vm_sizex_val/ (double)_vm_init_sizex ;
			_vm_sizeyscale_val = (double)_vm_sizey_val/ (double)_vm_init_sizey ;
			_vm_sizezscale_val = (double)_vm_sizez_val/ (double)_vm_init_sizez ;
			return ;
		}
		if (_vm_sizexscale || _vm_sizeyscale || _vm_sizezscale) {
			// some parameters have default values set in the port attr dialog
			if(_vm_sizexscale)	_vm_sizexscale_val = (* _vm_sizexscale) ;
			if(_vm_sizeyscale)	_vm_sizeyscale_val = (* _vm_sizeyscale) ;
			if(_vm_sizezscale)	_vm_sizezscale_val = (* _vm_sizezscale) ;	

			int ax = (int)((double) _vm_init_sizex * _vm_sizexscale_val);
			int ay = (int)((double) _vm_init_sizey * _vm_sizeyscale_val);
			int az = (int)((double) _vm_init_sizez * _vm_sizezscale_val);
			this->scaleBodyToAbsSize(ax,ay,az); 
			Ogre::Vector3 v = this->getActualSize();
			_vm_sizex_val = v.x ;  // restore the size information of this VM.
			_vm_sizey_val = v.y ;
			_vm_sizez_val = v.z ;
			return ;
		}
		return ;
	
	}

	// case 2: 
	//   (sizex, sizey, sizez) are connnected to variables but none of the (sizexscale, sizeyscale, sizezscale)
	//   are connected to variable         
	if ((_para_onoff[SIZE] || _para_onoff[SIZE+1] || _para_onoff[SIZE+2]) && 
		(_para_onoff[SCALE] == false && _para_onoff[SCALE+1] == false && _para_onoff[SCALE+2] == false)){	
	
			if(_vm_sizex != NULL)  _vm_sizex_val= (*_vm_sizex);
			if(_vm_sizey != NULL)  _vm_sizey_val= (*_vm_sizey);
			if(_vm_sizez != NULL)  _vm_sizez_val= (*_vm_sizez);
			this->scaleBodyToAbsSize(_vm_sizex_val,_vm_sizey_val,_vm_sizez_val ) ;
			// setting the size of a VM is equal to set the scale 
			_vm_sizexscale_val = (double)_vm_sizex_val/ (double)_vm_init_sizex ;
			_vm_sizeyscale_val = (double)_vm_sizey_val/ (double)_vm_init_sizey ;
			_vm_sizezscale_val = (double)_vm_sizez_val/ (double)_vm_init_sizez ;
			return ;
		
	}

	// case 3: 
	//   (sizex, sizey, sizez) are not connnected to variables 
	//   but some of the (sizexscale, sizeyscale, sizezscale)
	//   are connected to variable         
	if ((_para_onoff[SIZE]==false && _para_onoff[SIZE+1]==false && _para_onoff[SIZE+2]==false) && 
		(_para_onoff[SCALE] ||  _para_onoff[SCALE+1] ||  _para_onoff[SCALE+2])){	

		if(_vm_sizexscale)	_vm_sizexscale_val = (* _vm_sizexscale) ;
		if(_vm_sizeyscale)	_vm_sizeyscale_val = (* _vm_sizeyscale) ;
		if(_vm_sizezscale)	_vm_sizezscale_val = (* _vm_sizezscale) ;	

		int ax = (int)((double) _vm_init_sizex * _vm_sizexscale_val);
		int ay = (int)((double) _vm_init_sizey * _vm_sizeyscale_val);
		int az = (int)((double) _vm_init_sizez * _vm_sizezscale_val);
		this->scaleBodyToAbsSize(ax,ay,az); 
		Ogre::Vector3 v = this->getActualSize();
		_vm_sizex_val = v.x ;  // restore the size information of this VM.
		_vm_sizey_val = v.y ;
		_vm_sizez_val = v.z ;
		return ;
	}

	// case 4:
	//   (sizex, sizey, sizez) are connnected to variables but 
	//   some of the (sizexscale, sizeyscale, sizezscale)  are also connected to variable         
	//   this often occurs when a ubvm_wrapper has parallel connections to a set of default gates
	if ((_para_onoff[SIZE] || _para_onoff[SIZE+1] || _para_onoff[SIZE+2]) && 
		(_para_onoff[SCALE] || _para_onoff[SCALE+1] || _para_onoff[SCALE+2])) {
		if (_vm_sizex || _vm_sizey || _vm_sizez) {
			// some parameters have default value set in the portattr dialog
			if(_vm_sizex != NULL)  _vm_sizex_val= (*_vm_sizex);
			if(_vm_sizey != NULL)  _vm_sizey_val= (*_vm_sizey);
			if(_vm_sizez != NULL)  _vm_sizez_val= (*_vm_sizez);
			this->scaleBodyToAbsSize(_vm_sizex_val,_vm_sizey_val,_vm_sizez_val ) ;
			// setting the size of a VM is equal to set the scale 
			_vm_sizexscale_val = (double)_vm_sizex_val/ (double)_vm_init_sizex ;
			_vm_sizeyscale_val = (double)_vm_sizey_val/ (double)_vm_init_sizey ;
			_vm_sizezscale_val = (double)_vm_sizez_val/ (double)_vm_init_sizez ;
			return ;
		}
		if (_vm_sizexscale || _vm_sizeyscale || _vm_sizezscale) {
			// some parameters have default values set in the port attr dialog
			if(_vm_sizexscale)	_vm_sizexscale_val = (* _vm_sizexscale) ;
			if(_vm_sizeyscale)	_vm_sizeyscale_val = (* _vm_sizeyscale) ;
			if(_vm_sizezscale)	_vm_sizezscale_val = (* _vm_sizezscale) ;	

			int ax = (int)((double) _vm_init_sizex * _vm_sizexscale_val);
			int ay = (int)((double) _vm_init_sizey * _vm_sizeyscale_val);
			int az = (int)((double) _vm_init_sizez * _vm_sizezscale_val);
			this->scaleBodyToAbsSize(ax,ay,az); 
			Ogre::Vector3 v = this->getActualSize();
			_vm_sizex_val = v.x ;  // restore the size information of this VM.
			_vm_sizey_val = v.y ;
			_vm_sizez_val = v.z ;
			return ;
		}
		return ;
	}

	assert(false); // unforseen cases are reached

}
void DIVA_VM::update_size_and_scale(){
	
	init_size_and_scale();
}
void DIVA_VM::init_color_and_transparency() {

	if (_prohibit_defaults[SKIP_COLOR] == true)
		return ;

	assert(_vm_r_val >= 0.0 && _vm_g_val >= 0.0 && _vm_b_val >= 0.0) ;
	// the three variables should be set correctly in set_default_values
	
	if(_vm_r) _vm_r_val = *_vm_r ;
	if(_vm_g) _vm_g_val = *_vm_g ;
	if(_vm_b) _vm_b_val = *_vm_b ;

	if(_vm_transparency)  _vm_transparency_val = (*_vm_transparency);

	assert((_vm_r_val) >= 0.0 && (_vm_r_val) <= 1.0);
	assert((_vm_g_val) >= 0.0 && (_vm_g_val) <= 1.0);
	assert((_vm_b_val) >= 0.0 && (_vm_b_val) <= 1.0);
	assert((_vm_transparency_val) >= 0.0 && (_vm_transparency_val) <= 1.0);
	
	VL_setEntityColor(_ent,Ogre::Vector4(_vm_r_val, _vm_g_val, _vm_b_val, _vm_transparency_val));

}
void DIVA_VM::setColorandTransparency(Ogre::Vector4 v) {
	VL_setEntityColor(_ent,v);
}
void DIVA_VM::update_color_and_transparency() {

	init_color_and_transparency();
}
void DIVA_VM::init_rotation(){

	if (_prohibit_defaults[SKIP_ROTATION] == true)
		return ;
	assert(_vm_yaw_val != -9999  && _vm_pitch_val != -9999 && _vm_roll_val != -9999) ;
	// the three variables should be set correctly in set_default_values

	Ogre::Degree dyaw, dpitch, droll , preyaw , prepitch , preroll;
	if(_vm_yaw != NULL)	    { preyaw = Ogre::Degree(_vm_yaw_val);_vm_yaw_val = *_vm_yaw ; }
	if(_vm_pitch != NULL)	{ prepitch = Ogre::Degree(_vm_pitch_val);_vm_pitch_val = *_vm_pitch ; }
	if(_vm_roll != NULL)	{ preroll = Ogre::Degree(_vm_roll_val);_vm_roll_val = *_vm_roll ; }
	if(_vm_yaw_val < -360 || _vm_yaw_val > 360) {_vm_yaw_val = 0;}
	if(_vm_pitch_val < -360 || _vm_pitch_val > 360) {_vm_pitch_val = 0;}
	if(_vm_roll_val < -360 || _vm_roll_val > 360) {_vm_roll_val = 0;}
	dyaw = Ogre::Degree(_vm_yaw_val)-preyaw;
	dpitch = Ogre::Degree(_vm_pitch_val)-prepitch;
	droll = Ogre::Degree(_vm_roll_val)-preroll;
	
	_SceneNode->yaw(dyaw);
	_SceneNode->pitch(dpitch);
	_SceneNode->roll(droll);
}
void DIVA_VM::update_rotation(){
	init_rotation();
}

void DIVA_VM::init_quaternion() {

	if (_prohibit_defaults[SKIP_QUATERNION] == true) 
		return ;
}
void DIVA_VM::update_quaternion() {

	if (_prohibit_defaults[SKIP_QUATERNION] == true) 
		return ;
}
map<Ogre::MovableObject*,DIVA_VM*>* DIVA_VM::VL_getVMMovableObjectTable(){
	map<Ogre::MovableObject*,DIVA_VM*>* table;
	table = DIVA_Manager::getInstance()->get_vm_MovableObject_Table();
	return table;
} 

Ogre::Entity* DIVA_VM::VL_createEntity(string meshname, string materialname , string specialhead){
	assert(_mgr);

	Ogre::Entity* ent;
	
	if(specialhead == ""){
		ent = _mgr->createEntity(getNewUniqueName(),meshname);
	}
	else{
		ent = _mgr->createEntity(getNewUniqueName(specialhead),meshname);
	}
	if(materialname != ""){
		ent->getSubEntity(0)->setMaterialName(materialname);
	}	
	return ent;
}

void DIVA_VM::VL_setEntityColor(Ogre::Entity* target,Ogre::Vector4 colorvalue){
	Ogre::SubEntity* sub = target->getSubEntity(0);
	sub->setCustomParameter(COLOR_MODULATE_PARAM_INDEX,colorvalue);
}
void DIVA_VM::VL_regBoundingBox(Ogre::Entity* ent){
	DIVA_Manager::getInstance()->reg_MovableObj_VM_relation(ent,this);
}

void DIVA_VM::VL_arrangeVMs(vector<DIVA_VM*> child_vms){
	vector<DIVA_VM*>::iterator itr = child_vms.begin();
	for (itr = child_vms.begin();itr != child_vms.end(); itr++) {

		///先做ValueUpdated 調整成ddd的樣式
		//(*itr)->VMValueUpdated();

		// re-adjust scene node structure
		// we remove all the child vm's scenenode and add to this vm's _Scenenode

		Ogre::SceneNode *parent = (*itr)->getParentSceneNode() ;
		Ogre::SceneNode *s = (*itr)->getSceneNode();
		parent->removeChild(s);
		_SceneNode->addChild(s);
		(*itr)->setParentSceneNode(_SceneNode);
		s->setInheritScale(false); // we do not want child vm to be scale while a parent node is scaled
	}	
}


Ogre::Vector3 DIVA_VM::VL_computeMaxBoundingsize(std::vector<DIVA_VM*> child_vms, const DIVA_VM::Coordinate_axis& xMaxOrStretch, const DIVA_VM::Coordinate_axis& yMaxOrStretch, const DIVA_VM::Coordinate_axis& zMaxOrStretch){
	std::vector<DIVA_VM*>::iterator itr = child_vms.begin();
	assert(itr!= child_vms.end());
	Ogre::Vector3 sz = Ogre::Vector3(0,0,0);
	Ogre::Vector3 max = Ogre::Vector3(0,0,0);
 
	for(itr = child_vms.begin();itr!=child_vms.end();itr++){
		sz = (*itr)->getActualSize();
		if(xMaxOrStretch == X_Max && sz.x > max.x){			
			max.x = sz.x;
		}
		if(yMaxOrStretch == Y_Max && sz.y > max.y){
			max.y = sz.y;
		}
		if(zMaxOrStretch == Z_Max && sz.z > max.z){
			max.z = sz.z;
		}
		if(xMaxOrStretch == X_Positive_Stretch){
			max.x += sz.x;
		}
		if(yMaxOrStretch == Y_Positive_Stretch){
			max.y += sz.y;
		}
		if(zMaxOrStretch == Z_Positive_Stretch){
			max.z += sz.z;
		}		
	}

	return max;
}

Ogre::Vector3 DIVA_VM::VL_computeMinBoundingsize(vector<DIVA_VM*> child_vms,const Coordinate_axis& xMinOrStretch,const Coordinate_axis& yMinOrStretch,const Coordinate_axis& zMinOrStretch){
	std::vector<DIVA_VM*>::iterator itr = child_vms.begin();
	assert(itr!= child_vms.end());
	Ogre::Vector3 sz = Ogre::Vector3(0,0,0);
	Ogre::Vector3 min = Ogre::Vector3(99999,0,99999);
	for(itr = child_vms.begin();itr!=child_vms.end();itr++){
		sz = (*itr)->getActualSize();
		if(xMinOrStretch == X_Min && sz.x < min.x){
			min.x = sz.x;
		}
		if(yMinOrStretch == Y_Min && sz.y < min.y){
			min.y = sz.y;
		}
		if(zMinOrStretch == Z_Min && sz.z < min.z){
			min.z = sz.z;
		}
	}
	return min;
}

void DIVA_VM::VL_setVMsPosition(vector<DIVA_VM*>& child_vms,Ogre::Vector3 position,Ogre::SceneNode* parentnode){
	std::vector<DIVA_VM*>::iterator itr = child_vms.begin();
	assert(itr!= child_vms.end());
	Ogre::Vector3 pos;
	for(itr = child_vms.begin();itr!=child_vms.end();itr++){
		pos = (*itr)->getPosition();
		(*itr)->setPosition(position);
	}
	parentnode->setPosition(pos);	
}

void DIVA_VM::VL_minimizeVMsize(vector<DIVA_VM*>& child_vms,int defaultChildVMSize){
	std::vector<DIVA_VM*>::iterator itr = child_vms.begin();
	assert(itr!= child_vms.end());
	float min_scale = 0;
	Ogre::Vector3 childVMSize = Ogre::Vector3(0,0,0);
	for(itr = child_vms.begin();itr!=child_vms.end();itr++){
		childVMSize = (*itr)->getActualSize();
		min_scale = min(defaultChildVMSize / childVMSize.x , min(defaultChildVMSize / childVMSize.y,defaultChildVMSize / childVMSize.z));
	}
	if(min_scale > 1){
		min_scale = 1;
	}
	for(itr = child_vms.begin();itr!=child_vms.end();itr++){
		childVMSize = (*itr)->getActualSize();
		(*itr)->scaleBodyToAbsSize(Ogre::Vector3(childVMSize.x* min_scale , childVMSize.y* min_scale,childVMSize.z* min_scale));
	}	
}

Ogre::Vector3 DIVA_VM::VL_computeVarnamePosition(const DIVA_VM::TextPosition& textposition) {
	Ogre::Vector3 max_bounding = this->getActualSize();
	
	Ogre::Vector3 pos(0,0,0);
	int distance=50;
	if(textposition == FRONT){
		pos = Ogre::Vector3(0,0,(max_bounding.z/2+distance));
	} else 	if(textposition == BACK){
		pos = Ogre::Vector3(0,0,-(max_bounding.z/2+distance));
	} else 	if(textposition == LEFT){
		pos = Ogre::Vector3(-(max_bounding.x/2+distance),0,0);
	} else	if(textposition == RIGHT){
		pos = Ogre::Vector3((max_bounding.x/2+distance),0,0);
	} else 	if(textposition == TOP){
		pos = Ogre::Vector3(0,(max_bounding.y/2)+distance,0);
	} else 	if(textposition == BOTTOM){
		pos = Ogre::Vector3(0,-((max_bounding.y/2)+distance+TEXT_HEIGHT),0);
	} else	if(textposition == CENTER){
		pos = Ogre::Vector3(0,0,0);
	} else 
		assert(false);
	return pos ;
}
void DIVA_VM::VL_updateVarnamePosition() {
	Ogre::Vector3 pos(0,0,0);
	pos = VL_computeVarnamePosition((DIVA_VM::TextPosition)_vm_name_position);
	_text_scene_node->setPosition(pos);
}
Ogre::SceneNode* DIVA_VM::VL_createTextNode(const DIVA_VM::TextPosition &textposition, Ogre::Vector3 position, std::string specialhead){
	
	Ogre::Vector3 pos(0,0,0);
	pos = VL_computeVarnamePosition(textposition);
	Ogre::SceneNode* scenode;
	if(specialhead != ""){
		scenode = _SceneNode->createChildSceneNode(getNewUniqueName(specialhead),pos);
	}
	else{
		scenode = _SceneNode->createChildSceneNode(getNewUniqueName(this->getSceneNodeName()),pos);
	}	
	return scenode;
}

Ogre::MovableText* DIVA_VM::VL_createVMtext(std::string text,string specialhead){
	Ogre::MovableText* msg;
	if(specialhead != ""){
		msg = new Ogre::MovableText(getNewUniqueName(specialhead),text);
	}
	else{
		msg = new Ogre::MovableText(getNewUniqueName("MovableText"),text);
	}
	msg->setTextAlignment(Ogre::MovableText::H_CENTER, Ogre::MovableText::V_BELOW);
	msg->setCharacterHeight(TEXT_HEIGHT);		
	msg->setColor(Ogre::ColourValue(1.0, 1.0, 1.0, 1.0f));	
	return msg;
}

void DIVA_VM::VL_updateText(Ogre::MovableText* msg,std::string text){
	msg->setCaption(text);
}
bool DIVA_VM::isSubComponent(DIVA_VM *vm) {	
	if (vm == this) return true ;
	else return false ;
}
int DIVA_VM::VL_propagateMouseEvent(std::vector<DIVA_VM*> child_vms, Ogre::Vector3 clickpos){
	DIVA_VM* vm;
	DIVA_Manager* mgr = DIVA_Manager::getInstance();
	mgr->ray_scene_query(clickpos.x,clickpos.y);
	do {
		vm = mgr->pop_front_hitting_VM();
		if (vm != NULL) {
			int i = 0 ;
			std::vector<DIVA_VM *>::iterator itr ;
			for (itr = child_vms.begin(); itr != child_vms.end(); itr++) {
				DIVA_VM* child = (*itr);
				// some vm may not have entity but have a set of vms
				// as its body. In this case we must check if the clicked vm 
				// is its sub components or not. E.g., laser ref or container
				if (child->isSubComponent(vm)) {
					child->VMPicked(clickpos.x,clickpos.y,clickpos.z);
					return i;
				}
				i++ ;
			}
		}
	} while (vm != NULL);
	return -1 ;
}
int DIVA_VM::VL_propagateDraggedEvent(std::vector<DIVA_VM*> child_vms, 
									  Ogre::Vector3 clickpos,
									  Ogre::Vector3 abspos){
	DIVA_VM* vm;
	DIVA_Manager* mgr = DIVA_Manager::getInstance();
	mgr->ray_scene_query(clickpos.x,clickpos.y);
	do {
		vm = mgr->pop_front_hitting_VM();
		if (vm != NULL) {
			int i = 0 ;
			std::vector<DIVA_VM *>::iterator itr ;
			for (itr = child_vms.begin(); itr != child_vms.end(); itr++) {
				DIVA_VM* child = (*itr);
				// some vm may not have entity but have a set of vms
				// as its body. In this case we must check if the clicked vm 
				// is its sub components or not. E.g., laser ref or container
				if (child->isSubComponent(vm)) {
					child->VMDragged(clickpos.x, clickpos.y, abspos.x,abspos.y,abspos.z);
					return i;
				}
				i++ ;
			}
		}
	} while (vm != NULL);
	return -1 ;
}
void DIVA_VM::VL_addVMAnimation(){
	DIVA_Manager::getInstance()->addVMAnimationListener(this);
}

void DIVA_VM::updateByXpp( xParameterPack xpp ){
	
	assert(&xpp);

	//因為目前update沒有處理當vm_clone有給定_name
	//因此我先加assert
	assert(xpp.paras[0].val_string.empty());

	_vm_name_position=xpp.paras[1].val_int;

	if( xpp.para_onoff[RC] ) {
		this->_para_onoff[RC] = true;
		this->_vm_rx = xpp.paras[RC].val_float_ptr;
	}
	if( xpp.para_onoff[RC+1] ) {
		this->_para_onoff[RC+1] = true;
		this->_vm_ry = xpp.paras[RC+1].val_float_ptr;
	}
	if( xpp.para_onoff[RC+2] ) {
		this->_para_onoff[RC+2] = true;
		this->_vm_rz = xpp.paras[RC+2].val_float_ptr;
	}
	
	if( xpp.para_onoff[SIZE] ) {
		this->_para_onoff[SIZE] = true;
		this->_vm_sizex = xpp.paras[SIZE].val_float_ptr;
	}
	if( xpp.para_onoff[SIZE+1] ) {
		this->_para_onoff[SIZE+1] = true;
		this->_vm_sizey = xpp.paras[SIZE+1].val_float_ptr;
	}
	if( xpp.para_onoff[SIZE+2] ) {
		this->_para_onoff[SIZE+2] = true;
		this->_vm_sizez = xpp.paras[SIZE+2].val_float_ptr;
	}
	if( xpp.para_onoff[SCALE] ) {
		this->_para_onoff[SCALE] = true;
		this->_vm_sizexscale = xpp.paras[SCALE].val_double_ptr;
	}
	if( xpp.para_onoff[SCALE+1] ) {
		this->_para_onoff[SCALE+1] = true;
		this->_vm_sizeyscale = xpp.paras[SCALE+1].val_double_ptr;
	}
	if( xpp.para_onoff[SCALE+2] ) {
		this->_para_onoff[SCALE+2] = true;
		this->_vm_sizezscale = xpp.paras[SCALE+2].val_double_ptr;
	}
	
	if( xpp.para_onoff[RGB] ) {
		this->_para_onoff[RGB] = true;
		this->_vm_r = xpp.paras[RGB].val_double_ptr ;
	}
	if( xpp.para_onoff[RGB+1] ) {
		this->_para_onoff[RGB+1] = true;
		this->_vm_g = xpp.paras[RGB+1].val_double_ptr ;
	}
	if( xpp.para_onoff[RGB+2] ) {
		this->_para_onoff[RGB+2] = true;
		this->_vm_b = xpp.paras[RGB+2].val_double_ptr ;
	}
	if( xpp.para_onoff[TRANS] ) {
		this->_para_onoff[TRANS] = true;
		this->_vm_transparency = xpp.paras[TRANS].val_double_ptr ;
	}
	
	if( xpp.para_onoff[ROTATE] ) {
		this->_para_onoff[ROTATE] = true;
		this->_vm_yaw = xpp.paras[ROTATE].val_int_ptr ;
	}
	if( xpp.para_onoff[ROTATE+1] ) {
		this->_para_onoff[ROTATE+1] = true;
		this->_vm_pitch = xpp.paras[ROTATE+1].val_int_ptr ;
	}
	if( xpp.para_onoff[ROTATE+2] ) {
		this->_para_onoff[ROTATE+2] = true;
		this->_vm_roll = xpp.paras[ROTATE+2].val_int_ptr;
	}
	
	if( xpp.para_onoff[QUAT] ) {
		this->_para_onoff[QUAT] = true;
		this->_vm_quat = xpp.paras[QUAT].val_quaternion_ptr ;
	}
	
	if( xpp.para_onoff[CLICKMSG] ) {
		this->_para_onoff[CLICKMSG] = true;
		this->_vm_clickmsg = xpp.paras[CLICKMSG].val_string_ptr ;
	}
	_vm_clickmsg_position = xpp.paras[CLICKMSG+1].val_int ;
	
	DIVA_VM::VMValueUpdated();
}
